#!   /usr/bin/env lua
--[[

--]]
--require('mobdebug').start("127.0.0.1")

local Request = require("com.ea.core.request")
local Response = require("com.ea.core.response")
local db_monitor = require("luastar.db.monitor")
----local logger=logger;
local luastar_context=luastar_context;
local string=string;

-- 执行变量
local execute_var = {
    stop = false,
    status = 200
}

function init()
    -- 初始化应用包路径
    luastar_context.init_pkg_path()
    -- 获取路由
    execute_var["route"] = luastar_context.getRoute()
    execute_var["filter"] = luastar_context.getFilter();
    
    execute_var["ctrl_config"] = execute_var["route"]:getRoute(ngx.var.uri);
    execute_var["filter_list"] = assert(execute_var["filter"]:getFilterList(),"");
    if not execute_var["ctrl_config"] then
        ngx.log(ngx.ERR, logger.formatMsg("no ctrl find for : ", ngx.var.uri))
        execute_var["stop"] = true
        execute_var["status"] = 404
        return
    end
    
    
    -- 加载ctrl
    if ngx.var.APP_DEBUG_LOG== "true" then ngx.log(ngx.DEBUG,logger.formatMsg("execute_var[ctrl_config].class ",execute_var["ctrl_config"].class)) end
    local ok, ctrl = pcall(require, execute_var["ctrl_config"].class)
    if not ok then
        ngx.log(ngx.ERR, logger.formatMsg("ctrl import fail :", ctrl))
        execute_var["stop"] = true
        execute_var["status"] = 404
        return
    end
    execute_var["ctrl"] = ctrl
    -- 初始化输入输出
    ngx.ctx.request = Request:new()
    ngx.ctx.response = Response:new()
    -- 获取拦截器
    execute_var["interceptorAry"] = execute_var["route"]:getInterceptor(ngx.var.uri)
    
    if ngx.var.APP_DEBUG_LOG== "true" then ngx.log(ngx.DEBUG,logger.formatMsg("app_content:init end")) end
end

function content()
  --require('mobdebug').start('172.29.58.73')
    init()
    if execute_var["stop"] then
        -- openresty/1.7.10.1及以前版本的bug
        -- 必须调用ngx.req.read_body()或ngx.req.discard_body()处理请求体
        -- 因为第一个请求的请求体如果没有读取，会被错误地当作下一个请求的请求头来解析
        ngx.req.discard_body()
        ngx.ctx.response.responseJson(cjson.encode({state=4020002,msg="系统繁忙，请稍后再试",data=nil}));
        ngx.ctx.response.setHeader("Content-Type","application/json;charset=UTF-8");
        ngx.log(ngx.INFO,logger.formatMsg(string.format("request %s failed. HTTP status code %s ",ngx.var.uri,execute_var["status"])));
        return
    end
    
    --处理过滤器
    local ret_filter,err_filter;
    if   not _.isEmpty(execute_var["filter_list"])  then          
          for k,v in pairs(execute_var["filter_list"]) do  
              if ngx.var.APP_DEBUG_LOG== "true" then ngx.log(ngx.DEBUG,logger.formatMsg(string.format("class =%s  method=%s ",v.class,v.method))) end
              
              local  ok,filter_instance,ret_msg = pcall(require ,v.class)
              if ngx.var.APP_DEBUG_LOG== "true" then ngx.log(ngx.DEBUG,logger.formatMsg(string.format("filter_instance.type = %s ,filter_instance %s",type(filter_instance),filter_instance))) end
              if not ok then
                  ngx.log(ngx.ERR, logger.formatMsg(string.format("Filter %s  import fail,error is %s", v.class,filter_instance)))
                  execute_var["stop"] = true
                  execute_var["status"] = 500
                  break;
              end
           
              if filter_instance.new then
                  ret_filter,err_filter = execute_filter_new(filter_instance,v.method);                  
              else
                  ret_filter,err_filter = execute_filter_fun(v.class,v.method);
                  
              end
              if ngx.var.APP_DEBUG_LOG== "true" then ngx.log(ngx.DEBUG,logger.formatMsg(string.format("filter %s  return is %s ",v.class,ret_filter))); end
               
              if   ret_filter ~=true then
                  if ngx.var.APP_DEBUG_LOG== "true" then ngx.log(ngx.DEBUG,logger.formatMsg(string.format("filter class %s  method %s  error is %s  ,will set stop = true ",v.class,v.method,err_filter))); end
                  ngx.log(ngx.INFO,logger.formatMsg(string.format("filter stop  request process ,class %s  method %s  error is %s ",v.class,v.method,err_filter)));
                  execute_var["stop"]=true;    
                  execute_var["status"] = 500                                
                  break;
              end
          end
    end
    
    if execute_var["stop"] ~=true then
        if execute_var["ctrl"].new then
            execute_ctrl_new()
        else
            execute_ctrl_fun()
        end
    end
    -- 监控数据库连接
     
    db_monitor.check("redis_connect", "mysql_connect")
    if execute_var["stop"]==true then
       if ngx.ctx.response:isEof()==false then
          ngx.ctx.response:setHeader("Content-Type","application/json;charset=UTF-8");
          ngx.ctx.response:responseJson(cjson.encode({state=4020002,msg="系统繁忙，请稍后再试",data=nil}));       
          ngx.log(ngx.INFO,logger.formatMsg(string.format("request %s failed. HTTP status code %s ",ngx.var.uri,execute_var["status"])));
       end
    end
    ngx.ctx.response:finish()
    
    ngx.req.discard_body()
     --require('mobdebug').done();
end
--[[
       执行filter逻辑.过滤器计算满足条件，则返回true，否则返回false或者nil

   @return ret,err
     ret=true:成功
         false:计算失败，不允许后续逻辑，直接返回。
         nil：发生异常时候返回。
     err:发生异常时返回异常内容。
]]
function execute_filter_new(instance,strMethodName)
    if ngx.var.APP_DEBUG_LOG== "true" then ngx.log(ngx.DEBUG,logger.formatMsg(string.format("executefilternew :filter class  %s  method %s ", instance,strMethodName) )); end
    local filter_instance = instance:new()
    local filter_method = instance[strMethodName]
    if filter_method~=nil and _.isFunction(filter_method) then
        local call_ok, res_ok,res_msg = pcall(filter_method,filter_instance, ngx.ctx.request, ngx.ctx.response)
        if ngx.var.APP_DEBUG_LOG== "true" then ngx.log(ngx.DEBUG,logger.formatMsg(string.format("call_ok %s  err_info %s", call_ok, err_info))) end
        if call_ok ==true  then
            return res_ok,res_msg;
        else
          return false,res_msg;
        end;
    else
        ngx.log(ngx.ERR, logger.formatMsg("filter has no method:",strMethodName))
        execute_var["stop"] = true
        execute_var["status"] = 404
        return false,"mo method"
    end
end
--[[
       执行filter逻辑.过滤器计算满足条件，则返回true，否则返回false或者nil

   @return ret,err
     ret=true:成功
         false:计算失败，不允许后续逻辑，直接返回。
         nil：发生异常时候返回。
     err:发生异常时返回异常内容。
]]
function execute_filter_fun(instance,strMethod)
    if ngx.var.APP_DEBUG_LOG== "true" then ngx.log(ngx.DEBUG,logger.formatMsg("filter class  ",instance))     end
    
    local filter_method = instance[strMethod]
    if filter_method~=nil and _.isFunction(filter_method) then
        local call_ok, res_ok,res_msg = pcall(filter_method,  ngx.ctx.request, ngx.ctx.response)
        if call_ok ==ture  then
            return res_ok,res_msg;
        else
          return false,res_msg;
        end;
    else
        ngx.log(ngx.ERR, logger.formatMsg("filter has no method:",filter_method))
        execute_var["stop"] = true
        execute_var["status"] = 404
        return false,"mo method"
    end
end

--执行Service业务

function execute_ctrl_new()
    local interceptor_ok, interceptor_msg = execute_before()
    if not interceptor_ok then
        ngx.log(ngx.INFO, logger.formatMsg("interceptor ctrl success."))
        ngx.ctx.response:writeln(interceptor_msg)
        return
    end
    local ctrl_instance = execute_var["ctrl"]:new()
    local ctrl_method = ctrl_instance[execute_var["ctrl_config"].method]
    if ctrl_method and _.isFunction(ctrl_method) then
        local call_ok, err_info = pcall(ctrl_method, ctrl_instance, ngx.ctx.request, ngx.ctx.response)
        execute_after(call_ok, err_info)
    else
        ngx.log(ngx.ERR, logger.formatMsg("ctrl has no method."))
    end
end
--执行Service业务
function execute_ctrl_fun()
    local interceptor_ok, interceptor_msg = execute_before()
    if not interceptor_ok then
        ngx.log(ngx.INFO, logger.formatMsg("interceptor ctrl success."))
        ngx.ctx.response:writeln(interceptor_msg)
        return
    end
    local ctrl = execute_var["ctrl"]
    local ctrl_method = ctrl[execute_var["ctrl_config"].method]
    if ctrl_method and _.isFunction(ctrl_method) then
        local call_ok, err_info = pcall(ctrl_method, ngx.ctx.request, ngx.ctx.response)
        execute_after(call_ok, err_info)
    else
        ngx.log(ngx.ERR, logger.formatMsg("ctrl has no method."))
    end
end

function execute_before()
    if _.size(execute_var["interceptorAry"]) == 0 then
        return true, "no interceptor."
    end
    local call_ok, interceptor, rs_ok ,rs_msg= true, nil, true,nil;
    for key, value in pairs(execute_var["interceptorAry"]) do
        if ngx.var.APP_DEBUG_LOG== "true" then ngx.log(ngx.DEBUG,logger.formatMsg(string.format("interceptorAry %s",value))); end
        call_ok, interceptor = pcall(require, value)
        if call_ok and _.isFunction(interceptor["beforeHandle"]) then
            call_ok, rs_ok, rs_msg = pcall(interceptor["beforeHandle"])
            if call_ok then
                -- 有一个返回失败，则返回
                if not rs_ok then
                    return false, rs_msg or "intercept by interceptor."
                end
            else
                ngx.log(ngx.ERR,logger.formatMsg("interceptor call beforeHandle fail : ", rs_ok))
            end
        else
            ngx.log(ngx.ERR, logger.formatMsg("interceptor require fail : ", interceptor))
        end
    end
    return true, "not intercept by interceptor."
end

function execute_after(ctrl_call_ok, err_info)
    if not ctrl_call_ok then
        ngx.log(ngx.ERR, logger.formatMsg("ctrl execute error : ", err_info))
    end
    if _.size(execute_var["interceptorAry"]) == 0 then
        return
    end
    local call_ok, interceptor = true, nil
    for key, value in pairs(execute_var["interceptorAry"]) do
        call_ok, interceptor = pcall(require, value)
        if call_ok and _.isFunction(interceptor["afterHandle"]) then
            pcall(interceptor["afterHandle"], ctrl_call_ok, err_info)
        else
            ngx.log(ngx.ERR, logger.formatMsg("interceptor require fail : ", interceptor))
        end
    end
end

-- 执行
content()

--require('mobdebug').done()